iT邦幫忙

2025 iThome 鐵人賽

DAY 29
0
Software Development

Polars熊霸天下系列 第 29

[Day29] - 簡介marimo

  • 分享至 

  • xImage
  •  

marimo是資料科學領域的新星,可以視為新一代的notebook。其開發速度相當快,每隔一陣子就會有令人驚艷的新功能。

今天我們除了學習marimo的基礎知識外,還會使用marimo提供的widget建立如下的互動式表格(dark mode下錄制):

Django Deployment Checklist Animation

這是一個Django於部署前需要確認的表格,使用者可以點擊各確認事項的widget來標記檢查是否完成,並透過進度條得知整體進度。

本日大綱如下:

  1. 安裝及開啟marimo
  2. 認識marimo
  3. 建立互動式Django Deployment Checklist
  4. 小結

0. 安裝及開啟marimo

建議使用uv安裝:

uv add marimo

然候在命令列中執行:

marimo edit notebook.py

會在瀏覽器中開啟notebook.py(如果該路徑下沒有notebook.py的話,就會先建立後再開啟)。

此外,marimo有sandbox模式(使用--sandbox旗標),會在檔案一開頭記錄所使用的Python版本及依賴套件的版本,方便uv或WASM環境下使用。當需要在不同OS上執行notebook或是需要與其它團隊交換檔案時,特別好用。其格式會像是:

# /// script
# requires-python = ">=3.13"
# dependencies = [
#     "great-tables==0.18.0",
#     "polars==1.33.1",
# ]
# ///

1. 認識marimo

marimo在其GitHub repo是這麼描述這個專案:

A reactive Python notebook that's reproducible, git-friendly, and deployable as scripts or apps.

我們將從上述提到的四個面向來認識marimo:

  • Reactive
  • Reproducible
  • Git-friendly
  • Deployable as scripts or apps

Reactive

marimo notebook所有事物,都會因為變化而自動隨之變化。

舉例來說,現在有cell1cell2cell3運行如下:

# cell1
a = 1
# cell2
b = 2
# cell3
a + b # 3

此時,如果將cell1中的「"a"」改為2並執行:

# cell1
a = 2

cell3會自動變成:

# cell3
a + b # 4

這與Jupyter notebook有很大的不同,在Jupyter notebook中我們必須重新執行cell3,才會依照當下的狀態進行該cell的計算。

原理為marimo對notebook建立了directed acyclic graph (DAG),所以可以得知cell3的結果會受到cell1中變數的影響,進而自動重新計算cell3

值得一提的是,為了建構唯一且準確的DAG,marimo notebook不允許在不同cell中重複定義變數,例如:

# cell4
❌
a = 3
# This cell redefines variables from other cells.

但是如果是在同一個cell中重複定義則是允許的(因為仍然能解析出唯一的DAG),例如:

# cell5
✔️
c = 1
c = 2

最後,如果變數使用_(底線)開頭,則marimo notebook會視為各cell的局部變數,也就是該變數將無法在其它cell使用,例如:

# cell6
_a = 1
# cell7
❌
_a
# name '_a' is not defined

DAG確保marimo notebook是即時反映當下狀態,沒有隱藏狀態。

Reproducible

在marimo notebook中,由於是使用DAG判斷各cell的執行順序,所以各cell在marimo notebook中的順序並不重要。舉例來說,如果marimo notebook中的cell是如下的順序,在重啟kernel後仍可正常執行:

# cell1
a + b # 3
# cell2
a = 1
# cell3
b = 2

這點也與Jupyter notebook有很大的不同。在Jupyter notebook中,除了各cell的位置會影響初始計算外,使用者更常會於中途進行某些cell的操作,這將導致重啟kernel之後,難以重現預期的結果。

DAG確保marimo notebook的結果是唯一且可預期。

Git-friendly

由於Jupyter notebook是以JSON格式來儲存,這使得微小變動在git diff中,好像改變很多。

相比之下,marimo notebook只是一般的.py檔案,並不儲存計算結果,所以程式碼的微小變動僅會造成微小的git diff

marimo notebook的儲存格式就是單純的.py檔案。

Deployable as scripts or apps

marimo底層使用starlette,部署起來就像一般的ASGI,更可以和FastAPI搭配使用(畢竟FastAPI底層也是starlette嘛!)。

此外,marimo notebook提供了豐富的UI元素,讓使用者方便操作,而開發者可以透過各widget的.value屬性取得其值。這麼一來,使得marimo notebook能夠很容易地轉變為APP,並使用marimo run notebook.py部署。

最後,marimo notebook支援WASM,可透過官方提供的molab部署為WASM APP。

marimo notebook提供多種部署選項。

2. 建立互動式Django Deployment Checklist

此範例之marimo notebook檔案可下載回本機運行,或是直接上傳至molab,即刻部署為一個使用WASM的APP。

設定setup cell

Setup cell是一個特別的cell,marimo notebook會確保其是第一個執行的cell,特別適合用在引入模組時使用:

import marimo as mo
import polars as pl
from great_tables import GT, html, md

建立df dataframe

df dataframe共有三列:

  • 「"Status"」列作為標記各注意事項是否完成之用。暫時設為「"☐"」,等下會使用widget來代替。
  • 「"Task"」列代表部署前需要確認的事項(由AI產生)。
  • 「"Notes"」列為各確認事項的註記(由AI產生)。
tasks = [
    "Set DEBUG = False",
    "Configure ALLOWED_HOSTS",
    "Set up a secret key",
    "Collect static files",
    "Apply database migrations",
    "Set up gunicorn or uWSGI",
    "Configure reverse proxy (e.g., Nginx)",
    "Secure the database",
    "Set up HTTPS (SSL)",
    "Configure logging & monitoring",
]

notes = [
    "Never deploy with DEBUG = True ⚠️",
    "Include your domain(s) or IP address 🌐",
    "Use a strong, secure key from an environment variable 🔐",
    "Run `python manage.py collectstatic` 📦",
    "Run `python manage.py migrate` 🗃️",
    "Use as a WSGI server in production 🔄",
    "Serve static/media files and forward to WSGI server 🧭",
    "Use strong credentials, disable remote root login 🛡️",
    "Use Let's Encrypt or your own certificate 🔒",
    "Track errors and app performance 📊",
]

n_row = len(tasks)
status = ["☐"] * n_row
data = {"Status": status, "Task": tasks, "Notes": notes}
df = pl.DataFrame(data)
df

Marimo DataFrame

如果仔細觀察,可以發現df在marmimo notebook介面中,有不少可以點擊的UI工具,方便快速進行資料探勘。

建立status widgets

建立一個包含十個mo.ui.switchmo.ui.array

status_widget = mo.ui.switch()
status_widgets = mo.ui.array([status_widget] * n_row)

建立create_bar()函數

create_bar()的靈感來自於Great Tables提供的範例,將作為進度條使用。

def create_bar(
    x: float,
    max_width: int,
    height: int,
    background_color1: str,
    background_color2: str,
) -> str:
    width = round(max_width * x, 2)
    px_width = f"{width}px"
    return f"""\
    <div style="width: {max_width}px; background-color: {background_color1};">\
        <div style="height:{height}px;width:{px_width};background-color:{background_color2};"></div>\
    </div>\
    """

建立互動式表格

使用Great Tables建立此互動式表格(light mode下截圖)。

done_count = sum(s.value for s in status_widgets)

gt = (
    GT(
        df.with_columns(
            pl.Series(
                [status._repr_html_() for status in status_widgets]
            ).alias("Status")
        )
    )
    .tab_source_note(f"{done_count} / {n_row}")
    .tab_source_note(
        html(
            create_bar(
                done_count / n_row,
                max_width=750,
                height=20,
                background_color1="lightgray",
                background_color2="#66CDAA",
            )
        )
    )
    .tab_header("✅ Django Deployment Checklist")
    .opt_stylize(color="cyan", style=4)
)
gt

Django Deployment Checklist

簡單說明如下:

  • 使用各widget的_repr_html_()來替換原先為「"☐"」的「"Status"」列,這是表格由靜態成為互動的關鍵,詳細原因請參考marimo教學文件
  • 使用兩次GT.tab_source_note()來加入進度條及顯示數字。
  • 使用GT.tab_header()加入標題。
  • 使用GT.opt_stylize()調整表格外觀。

3. 小結

今天我們學習了marimo最基礎的用法,如果您有興趣想更深入了解,可以參考這段YouTube影片,Vincent列舉了十多個marimo的特色及小技巧,相當值得一看!

最後,如果對於Great Tables在marimo中的應用有興趣的朋友,可以看看參考資料中所列的部落格文章,今天的範例內容來自參考資料2。

參考資料

  1. 個人部落格文章:Great Tables with marimo in Quarto
  2. 個人部落格文章:Interactive Django Deployment Checklist with marimo
  3. 個人部落格文章:Send Email via marimo
  4. 個人部落格文章:Time Machine for Great Tables in marimo
  5. 個人部落格文章:Creating an Integrated marimo UI Explorer with Great Tables

Code

本日程式碼傳送門


上一篇
[Day28] - 簡介Pointblank
系列文
Polars熊霸天下29
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言